//提供一些公共的结构，避免import cycle，导致无法编译通过
package core

import (
	"time"
	"errors"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"gitee.com/siruihuyu/appapi/core/unixtime"
	"crypto/hmac"
	"crypto/sha256"
	"io"
)



//error相关的常量
const (
	//体力扣除失败
	EnergyTakeOffFail = `energy take off fail`
	//体力值已经出现负数
	EnergyValueBad = `energy value bad`

)

type List []int64

type Goods struct {
	//类型
	Type int32
	//数量
	Num int32
	//道具花费--在被使用的时候用来计算收益
	Cost []int32
}

type GoodsList []Goods

func (b GoodsList) Value() (driver.Value, error) {
	return json.Marshal(b)
}

func (b *GoodsList) Scan(src interface{}) error {
	v,ok := src.([]byte)
	if !ok {
		return errors.New("bad []byte type assertion")
	}
	return  json.Unmarshal(v, b)
}

func (l List) Value() (driver.Value, error)  {
	return json.Marshal(l)
}

func (l *List) Scan(src interface{}) error {
	if src == nil {
		*l = make(List, 0)
		return nil
	}
	v,ok := src.([]byte)
	if !ok {
		return errors.New("bad []byte type assertion")
	}
	return json.Unmarshal(v, l)
}

type Energy struct {
	Energy     int32 `db:"energy" json:"energy"`
	EnergyTime unixtime.Time  `db:"energy_time" json:"energy_time"`
}

//根据上一次更新的时间，重新计算体力值，并重新计算更新时间
//等于30的体力，在被扣除体力时，energyTime为当前时间
//低于30体力时，再被扣除和新增后，在原来的energyTime的基础上增加通过时间差增加的体力的时间
//energy
func CalculationEnergy(energy *Energy, change int32, roleDefaultEnergy, energyRecoveryTime int32) (error) {
	v := energy.Energy
	if v >= roleDefaultEnergy { //初始值已达到上限
		v = roleDefaultEnergy //修正数据
		v = v + change
		if v >= 0 {
			if v >= roleDefaultEnergy {
				v = roleDefaultEnergy //修正数据
			}
			energy.Energy = v
			energy.EnergyTime = unixtime.Now()
			return nil
		} else {
			return fmt.Errorf(EnergyTakeOffFail)
		}
	} else {
		dif := time.Now().Unix() - energy.EnergyTime.Unix()
		add := int32(dif)/ energyRecoveryTime
		//当前应该的体力值
		v = v + add
		if v >= roleDefaultEnergy { //初始值已达到上限
			v = roleDefaultEnergy //修正数据
			v = v + change
			if v >= 0 {
				if v >= roleDefaultEnergy {
					v = roleDefaultEnergy //修正数据
				}
				energy.Energy = v
				energy.EnergyTime = unixtime.Now()
				return nil
			} else {
				return fmt.Errorf(EnergyTakeOffFail)
			}
		} else if v < 0 {
			return fmt.Errorf(EnergyValueBad)
		} else {//初始值未达上限
			v = v + change
			if v >= roleDefaultEnergy { //改变后达到上限
				v = roleDefaultEnergy
				energy.Energy = v
				energy.EnergyTime = unixtime.Now()
			} else if v < 0 {
				return fmt.Errorf(EnergyTakeOffFail)
			} else {//改变后仍为达到上限
				//需要在EnergyTime的基础上加上转换为体力的时间
				m, _ := time.ParseDuration("5m")
				newTime := time.Time(energy.EnergyTime).Add(m * time.Duration(add))
				energy.EnergyTime = unixtime.Time(newTime)
				energy.Energy = v
			}
		}
	}

	return nil
}

//数组去重
func RemoveDuplicate(list List) (List) {
	var result List
	dic := make(map[int64]bool)

	for _, element := range list {
		if !dic[element] {
			dic[element] = true
			result = append(result, element)
		}
	}

	return result
}

type WXLoginSt struct {
	WXCode CodeSt   `json:"wx_code"`
	Info   RoleInfo `json:"info"`
	IV string `json:"iv"`
	EncryptedData string `json:"encryptedData"`
}

type CodeSt struct {
	ErrMsg string `json:"errMsg"`
	Code   string `json:"code"`
}

type RoleInfo struct {
	AvatarUrl string `json:"avatarUrl"`
	City      string `json:"city"`
	Country   string `json:"country"`
	Gender    uint8  `json:"gender"`
	Language  string `json:"language"`
	NickName  string `json:"nickName"`
	Province  string `json:"province"`
}

type Code2Session struct {
	//用户唯一标识
	Openid string `json:"openid"`
	//会话密钥
	SessionKey string `json:"session_key"`
}

//s 加密的的字符串
//key 加密的key--微信小游戏传米大师的key
func GetHmacCode(s string,key string) string {
	h := hmac.New(sha256.New, []byte(key))
	io.WriteString(h, s)
	return fmt.Sprintf("%x", h.Sum(nil))
}
